using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.Linq;
using Circa;
using Circa.Tools;

namespace Circa.Protocol.Irc {

    public struct TopicInfo {
        public string Topic;
        public string SetBy; // XXX should be UserEntity
        public DateTime SetAt;

        public override string ToString( ) {
            return Topic;
        }
    }

    public class Channel: ITargetable {
        public string Name { get; set; }
        public string Description { get; set; }
        public string Key { get; set; }
        public bool AutoJoin { get; set; }

        public Network Network { get; set; }
        public Server Server { get; set; }

        public string Mode { get; set; } // XXX should be a ChannelModeInfo object that has a(n implicit?) conversion to type string
        public virtual IList<TopicInfo> TopicInfo { get; internal set; }

        protected SafeDictionary<string, Action<IrcMessage>> verbs;

        public Channel( ) {
            TopicInfo = new List<TopicInfo>( );
            verbs = new SafeDictionary<string, Action<IrcMessage>> {
                { "324", RplChannelModeIs },
                { "332", RplTopic },
                { "353", RplNamReply },
                { "366", RplEndOfNames },
                { "367", RplBanList },
                { "368", RplEndOfBanList },
            };
        }

        public Channel( Network parent, Configuration.Channel conf ): this( ) {
            Name = conf.Name;
            Description = conf.Description;
            Key = conf.Key;
            AutoJoin = conf.AutoJoin;

            Network = parent;
        }

        public event EventHandler<EventArgs> Joined;
        protected virtual void OnJoined( EventArgs e ) {
            var handler = Joined;
            if ( null != handler )
                handler( this, e );
        }

        public virtual bool Dispatch( IrcMessage m ) {
            Action<IrcMessage> handler = verbs[ m.Verb ];
            if ( null != handler ) {
                handler( m );
                return true;
            }

            return false;
        }

        public void RplChannelModeIs( IrcMessage m ) {
            Debug.Print( "Channel.RplChannelModeIs: channel mode={{{0}}}", m.Args[ 0 ] );
            Mode = m.Args[ 0 ];
            // TODO
        }

        public void RplTopic( IrcMessage m ) {
            Debug.Print( "Channel.RplTopic: topic={{{0}}}", m.Args[ 0 ] );

            TopicInfo.Insert( 0, new TopicInfo { Topic = m.Args[ 0 ] } );
        }

        public void RplNamReply( IrcMessage m ) {
            // TODO
            // m.Args[0]: '*' => Prv (+p)
            //            '@' => Sec (+s)
            //            '=' => Pub (-ps)
            // m.Args[1]: space-separated list of <prefix><nick>
        }

        public void RplEndOfNames( IrcMessage m ) {
            // TODO
        }

        public void RplBanList( IrcMessage m ) {
            // TODO
        }

        public void RplEndOfBanList( IrcMessage m ) {
            // TODO
        }

        public void JOIN( IrcMessage m ) {
            OnJoined( EventArgs.Empty );
            Server.Perform.Who( Name );
        }

    }

}
